package com.robot.backend.consumer;

import cn.dev33.satoken.stp.StpUtil;
import com.alibaba.fastjson2.JSONObject;
import com.robot.backend.mapper.RobotMapper;
import com.robot.backend.mapper.UserMapper;
import com.robot.backend.pojo.User;
import jakarta.websocket.*;
import jakarta.websocket.server.PathParam;
import jakarta.websocket.server.ServerEndpoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
import com.robot.backend.utils.gameMap.game;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.SerializationUtils;
import org.springframework.web.client.RestTemplate;
import com.robot.backend.mapper.RobotMapper;

@Component
@ServerEndpoint("/websocket/{token}")  // 注意不要以'/'结尾
public class WebSocketServer {

    //在java中，静态变量是对所有对象都可可见的，不加则是每一个对象都独一份
    //存储用户id和链接的对应关系，可以通过id找到链接
    final public static ConcurrentHashMap<Integer,WebSocketServer> users = new ConcurrentHashMap<>();
    //private static final CopyOnWriteArraySet<User> matchPool = new CopyOnWriteArraySet<>();
    public static RestTemplate restTemplate;
    private User user;//websocket对应连接的用户
    private Session session=null;

    public static UserMapper userMapper;
    public static RobotMapper robotMapper;
    public game game;
    final static private Map<Integer,Integer> botIds = new HashMap<>();
    //记录id与bot对应关系,当开始匹配时，记录用户选择了哪个bot，取消匹配时移出

    private final static String addPlayerURL="http://127.0.0.1:3001/player/add/";
    private final static String removePlayerURL="http://127.0.0.1:3001/player/remove/";

    public final static String addBotURL="http://127.0.0.1:3002/botRunning/addBot/";

    @Autowired
    public void setUserMapper(UserMapper userMapper){
        WebSocketServer.userMapper=userMapper;
    }
    @Autowired
    public void setRobotMapper(RobotMapper robotMapper){
        WebSocketServer.robotMapper=robotMapper;
    }
    @Autowired
    public void setRestTemplate(RestTemplate restTemplate) {WebSocketServer.restTemplate=restTemplate;}

    private boolean isBot(int bid){
        if(bid == 0) return false;
        else return true;
    }
    public void cancelBotUserBind(int uid){
        botIds.remove(game.getPlayer1().getId());
        botIds.remove(game.getPlayer2().getId());
    }
    public void startGame(int aid,int bid,int winScore, int lostScore) {
        User a = userMapper.selectById(aid);
        User b = userMapper.selectById(bid);
        game =new game(13,14,20,a.getId(),b.getId());
        game.createMap();
        //game.gRes = game.g;不要这样重新赋值，是同一个指针
        game.gRes = SerializationUtils.clone(game.g);


        users.get(a.getId()).game = game;
        users.get(b.getId()).game = game;

        game.setDeta(Math.abs((a.getScore()-b.getScore())));
        game.setBotId(a.getId(),botIds.get(game.getPlayer1().getId()));
        game.setBotId(b.getId(),botIds.get(game.getPlayer2().getId()));

        int abotId = game.getPlayer1().getBotid();
        int bbotId = game.getPlayer2().getBotid();
        System.out.println("执行的botid:"+abotId+"和"+bbotId);
//        botIds.remove(game.getPlayer1().getId());
//        botIds.remove(game.getPlayer2().getId());
        int Kmax = 100;//上限
        int Kbase = 50;//幅度
        int d = Math.abs((a.getScore()-b.getScore()));
        int sc;
        if(d == 0) sc=Kmax;
        else sc = (Kmax*Kbase) / d;

        JSONObject gameInfo = new JSONObject();
        gameInfo.put("aid",game.getPlayer1().getId());
        gameInfo.put("asx",game.getPlayer1().getSx());
        gameInfo.put("asy",game.getPlayer1().getSy());
        gameInfo.put("bid",game.getPlayer2().getId());
        gameInfo.put("bsx",game.getPlayer2().getSx());
        gameInfo.put("bsy",game.getPlayer2().getSy());
        gameInfo.put("map",game.getG());
        gameInfo.put("winScore",sc);
        gameInfo.put("loseScore",-sc);

        JSONObject resA=new JSONObject();
        resA.put("event","success");
        resA.put("oppoUserName",b.getName());
        resA.put("oppoUserPhoto",b.getPhoto());
        resA.put("gameInfo",gameInfo);
        users.get(a.getId()).sendMessage(resA.toJSONString());//通过wss协议传给前端
        JSONObject resB = new JSONObject();
        resB.put("event","success");
        resB.put("oppoUserName",a.getName());
        resB.put("oppoUserPhoto",a.getPhoto());
        resB.put("gameInfo",gameInfo);
        users.get(b.getId()).sendMessage(resB.toJSONString());//通过wss协议传给前端
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        game.start();//线程api,game类的入口
    }
    private void startMarching(String token,int botId){
        System.out.println("start Matching");
        int id = Integer.parseInt(StpUtil.getLoginIdByToken(token).toString());
        this.user=userMapper.selectById(id);//更新user获取最新数据
        botIds.put(id,botId);
        MultiValueMap<String,String> multiValueMap = new LinkedMultiValueMap<>();
        multiValueMap.add("userid",this.user.getId().toString());
        multiValueMap.add("score",this.user.getScore().toString());
        multiValueMap.add("botid", String.valueOf(botIds.get(this.user.getId())));
        restTemplate.postForObject(addPlayerURL,multiValueMap,String.class);//返回值的class
        //简单匹配
//        matchPool.add(this.user);
//        while(matchPool.size() >= 2){
//            Iterator<User> it =matchPool.iterator();
//            User a =it.next(),b=it.next();
//            matchPool.remove(a);
//            matchPool.remove(b);
//            System.out.println("匹配成功");
//
//
//        }
    }
    private void stopMarching(int id){
        MultiValueMap<String,String> multiValueMap = new LinkedMultiValueMap<>();
        multiValueMap.add("userid",this.user.getId().toString());
        botIds.remove(id);
        restTemplate.postForObject(removePlayerURL,multiValueMap,String.class);
//        matchPool.remove(this.user);
    }
    @OnOpen
    public void onOpen(Session session, @PathParam("token") String token) {//相当于构造函数
        // 建立连接
        this.session = session;
        int id = Integer.parseInt(StpUtil.getLoginIdByToken(token).toString());
        this.user=userMapper.selectById(id);
        users.put(id,this);
    }

    @OnClose
    public void onClose() {
        // 关闭链接
        if(this.user != null){
            users.remove(this.user.getId());
            //remove(this.user);
        }

    }

    private void move(int direction){//收到前端的move类信息时,前端键盘控制
        if(game.getPlayer1().getId() == user.getId())
            if(game.getPlayer1().getBotid() == 0)
                game.setStepA(direction);
        if(game.getPlayer2().getId() == user.getId())
            if(game.getPlayer2().getBotid() == 0)
                game.setStepB(direction);
        //如果是由player1发来的设置方向请求，并且需要人来操作时
//        if(game.getPlayer1().getId() == user.getId() && botIds.get(game.getPlayer1().getId()) == 0)
//            game.setStepA(direction);
//        if(game.getPlayer2().getId() == user.getId() && botIds.get(game.getPlayer2().getId()) == 0)
//            game.setStepB(direction);
    }
    @OnMessage
    public void onMessage(String message, Session session,@PathParam("token") String token) {//相当于路由，根据前端传来的event字符串走不同函数
        // 从Client接收消息
        JSONObject data=JSONObject.parseObject(message);
        String event = data.getString("event");
        int id = Integer.parseInt(StpUtil.getLoginIdByToken(token).toString());
        if("start".equals(event)){
            startMarching(token,Integer.parseInt(data.getString("botId")));
        }else if("stop".equals(event))
            stopMarching(id);
        else if("move".equals(event))
            move(Integer.parseInt(data.get("direction").toString()));
    }

    @OnError
    public void onError(Session session, Throwable error) {
        error.printStackTrace();
    }

    public void sendMessage(String message){
        RemoteEndpoint.Async asyncRemote = session.getAsyncRemote();
        asyncRemote.sendText(message);//向另一端发送信息
    }
}